package itpenguin.review;

import itpenguin.common.PMFactory;
import itpenguin.review.entities.Item;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ListServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static final int ITEMS_PER_PAGE = 30;
	private static final String SELECT_STATEMENT = "select from itpenguin.review.entities.Item ";
	private static final String COUNT_STATEMENT = "select count(this) from itpenguin.review.entities.Item ";

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws  IOException, ServletException {

		String pathinfo = req.getPathInfo();
		String servletPath = req.getServletPath();
		int beginRange = 0;
		long endRange = 0;
		int currentPage = 0;
		int maxPage = 0;
		long totalCount = 0;
		String additionalStmt = null;
		String currentPgStr = null;

		if (pathinfo == null) {
			resp.sendError(HttpServletResponse.SC_NOT_FOUND);
			return;
		}

		PersistenceManager pm = PMFactory.getInstance().getPersistenceManager();
		List<Item> reviewList = null;
		String pathInfo = req.getPathInfo();
		String[] info = pathInfo.split("/");
		Map<String, Object> params = new HashMap<String, Object>();

		if (servletPath.equals("/rating")) {
			if (info.length != 3) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}

			short rating;
			try {
				rating = Short.parseShort(info[1]);
			} catch (NumberFormatException e) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			if (rating < 0 || rating > 10) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			currentPgStr = info[2];
			req.setAttribute("rating", rating);
			additionalStmt = "where numberOfStars == numberOfStarParams "
					+ "parameters int numberOfStarParams "
					+ "order by reviewDate desc";
			params.put("numberOfStarParams", rating);
		} else if (servletPath.equals("/archives")) {
			if (info.length != 3 && info.length != 4) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}

			short year;
			short month;
			short range;
			try {
				if (info.length == 3) {
					year = Short.parseShort(info[1]);
					month = 1;
					range = 12;
					currentPgStr = info[2];
				} else {
					year = Short.parseShort(info[1]);
					month = Short.parseShort(info[2]);
					if (month < 0 || month > 12 || year < 2012) {
						throw new NumberFormatException();
					}
					range = 1;
					currentPgStr = info[3];
				}
			} catch (NumberFormatException e) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			
			Calendar cal = Calendar.getInstance();
			cal.setTimeZone(TimeZone.getTimeZone("JST"));
			cal.set(year, month - 1, 1, 0, 0, 0);
			Date beginDate = cal.getTime();
			cal.add(Calendar.MONTH, range);
			Date endDate = cal.getTime();
			additionalStmt = "where reviewDate >= beginDateParam "
					+ "&& reviewDate < endDateParam "
					+ "parameters java.util.Date beginDateParam, "
					+ "java.util.Date endDateParam "
					+ "order by reviewDate desc";
			params.put("beginDateParam", beginDate);
			params.put("endDateParam", endDate);
			
			req.setAttribute("beginDate", beginDate);
			req.setAttribute("range", range);
		} else if (servletPath.equals("/all")) {
			if (info.length != 2) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			additionalStmt = "order by reviewDate desc";
			currentPgStr = info[1];
		} else if (servletPath.equals("/allrank")) {
			if (info.length != 2) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			additionalStmt = "order by score desc";
			req.setAttribute("all", "rank");
			currentPgStr = info[1];
		} else if (servletPath.equals("/rank")) {
			if (info.length != 3) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			short year;
			try {
				year = Short.parseShort(info[1]);
			} catch (NumberFormatException e) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			currentPgStr = info[2];
			additionalStmt = "where reviewYear == yearParam "
					+ "parameters int yearParam, "
					+ "order by score desc";
			params.put("yearParam", year);
			req.setAttribute("year", year);
		}
		
		try {
			currentPage = Integer.parseInt(currentPgStr);
		} catch (NumberFormatException e) {
			resp.sendError(HttpServletResponse.SC_NOT_FOUND);
			return;
		}
		
		Query query = pm.newQuery(COUNT_STATEMENT + additionalStmt);   
		totalCount = (Long)query.executeWithMap(params);
		beginRange = (currentPage - 1) * ITEMS_PER_PAGE;
		endRange = beginRange + ITEMS_PER_PAGE;
		if (endRange > totalCount) 
			endRange = totalCount;
		maxPage = (int)(totalCount / ITEMS_PER_PAGE) + (totalCount % ITEMS_PER_PAGE == 0 ? 0 : 1);
		
		query = pm.newQuery(SELECT_STATEMENT + additionalStmt);   
		query.setRange(beginRange, endRange);
		reviewList = (List<Item>) query.executeWithMap(params);
		req.setAttribute("reviewList", pm.detachCopyAll(reviewList));
		pm.close();
		
		if (reviewList.size() == 0) {
			resp.addDateHeader("Last-Modified", 0);
		} else {
			resp.addDateHeader("Last-Modified", reviewList.get(0).getLastModified().getTime());
		}

		req.setAttribute("beginRange", beginRange);
		req.setAttribute("endRange", endRange);
		req.setAttribute("currentPage", currentPage);
		req.setAttribute("maxPage", maxPage);
		req.setAttribute("totalCount", totalCount);
		req.setAttribute("context", 
				servletPath + pathInfo.substring(0, pathInfo.lastIndexOf('/')));
		
		RequestDispatcher rd = req.getRequestDispatcher("/WEB-INF/template/main.jsp");
		rd.forward(req, resp);
	}

}
